#!/usr/bin/python3
import subprocess
import sys
import pwd
import grp
import os
import signal
import wiringpi
import numpy as np
import multiprocessing.shared_memory # 共享内存
import threading
import time
import logging
import datetime

LedControlPin = 7 # 状态指示灯的wiringpi Pin
# 创建两个共享内存，大小为 1 个整数
status_IMU_Proc = multiprocessing.shared_memory.SharedMemory(create=True, size = np.dtype('int').itemsize)
status_Depth_Proc = multiprocessing.shared_memory.SharedMemory(create=True, size = np.dtype('int').itemsize)
# 将共享内存映射到一个 NumPy 数组
# normal = 0x00
# initOK = 0x10
# SerialErr = 0x01 # 初始化中串口丢失，检查设备是否连接，两个USB设备的设备号是否接错
# runningSerialErr = 0x02 # 设备运行中串口丢失，检查设备是否有松动
# UndefinedErr = 0x0a
shared_IMU_buf = np.ndarray((1,), dtype=np.int32, buffer=status_IMU_Proc.buf)
shared_IMU_buf[0] = 0x00
shared_Depth_buf = np.ndarray((1,), dtype=np.int32, buffer=status_Depth_Proc.buf)
shared_Depth_buf[0] = 0x00

processes = []  # 存储子进程对象的列表
def run_script(script_path, buffName):
    try:
        # 使用Popen的返回值来获取子进程的引用
        process = subprocess.Popen(['/usr/bin/python3', script_path, os.path.basename(script_path), buffName])
        print(f"Started script: {script_path}")
        return process  # 返回子进程对象
    except Exception as e:
        print(f"Error starting script: {script_path}")
        print(f"Error message: {str(e)}")
        return None
def terminateAllProcess(processList):
    for process in processList:
        if process.poll() is None:  # 检查进程是否仍在运行
            process.terminate()
    status_IMU_Proc.close() # 关闭共享内存
    status_Depth_Proc.close() # 关闭共享内存

def handle_sigterm(signum, frame):
    global processes
    terminateAllProcess(processes)
    sys.exit(0)
signal.signal(signal.SIGTERM, handle_sigterm)

def controlIndicatorLight(high):
    if high:
        # print("DEBUG, LedControl HIGH")
        wiringpi.digitalWrite(LedControlPin, 1)
    else:
        # print("DEBUG, LedControl LOW")
        wiringpi.digitalWrite(LedControlPin, 0)

def main():
    # 指示灯
    wiringpi.wiringPiSetup()
    # 指示灯功能打开
    wiringpi.pinMode(LedControlPin, 1)
    controlIndicatorLight(False)
    wiringpi.delay(500)
    controlIndicatorLight(True)
    wiringpi.delay(350)
    controlIndicatorLight(False)
    wiringpi.delay(350)
    controlIndicatorLight(True)
    wiringpi.delay(350)
    controlIndicatorLight(False)
    wiringpi.delay(350)
    controlIndicatorLight(True)
    wiringpi.delay(350)
    controlIndicatorLight(False)

    global processes
    global status_IMU_Proc
    global status_Depth_Proc

    script_paths = [
        # 'src/MS5837/read_ms5837.py',
        # 'src/N300/IMU.py',
        # 'src/PMC3000/IMU_2.py'
        'src/HWT9073_CAN/Read_HWT9073_CAN.py',
        'src/DT03D5_RS485/Read_DT03D5.py'
    ]
    buff = [
        status_IMU_Proc.name,
        status_Depth_Proc.name
    ]
    # 设置 SIGTERM 信号处理程序

    try:
        for index, script_path in enumerate(script_paths):
            time.sleep(1.333) # 稍等一会再启动另一个进程
            process = run_script(script_path, buff[index])
            if process:  # 如果成功启动了子进程，则将其添加到列表中
                processes.append(process)
            else:
                terminateAllProcess(processes)
                sys.exit(1)
        
        # 等待所有子进程结束
        for process in processes:
            process.wait()

    except KeyboardInterrupt:
        print("Ctrl+C pressed. Stopping all scripts...")
        terminateAllProcess(processes)
        # 等待所有子进程确实停止
        for process in processes:
            process.wait()
        print("All scripts stopped.")
    

def check_subprocess():
    global shared_IMU_buf
    global shared_Depth_buf

    # logging.basicConfig(filename='Data/log.txt', level=logging.INFO, filemode='w')

    if shared_IMU_buf[0] == 0x10:
        logging.info(f"{datetime.datetime.now()} - 主进程 : 检测到IMU初始化正常")
    elif shared_IMU_buf[0] == 0x01:
        logging.info(f"{datetime.datetime.now()} - 主进程 : 检测到IMU初始化失败")
        return 0x01, 0x01
    elif shared_IMU_buf[0] == 0x02:
        logging.info(f"{datetime.datetime.now()} - 主进程 : 检测到IMU运行时串口异常")
        return 0x01, 0x02
    elif shared_IMU_buf[0] == 0x00:
        logging.info(f"{datetime.datetime.now()} - 主进程 : 检测到IMU设备未初始化")

    if shared_Depth_buf[0] == 0x10:
        logging.info(f"{datetime.datetime.now()} - 主进程 : 检测到深度计初始化正常")
    elif shared_Depth_buf[0] == 0x01:
        logging.info(f"{datetime.datetime.now()} - 主进程 : 检测到深度计初始化失败")
        return 0x02, 0x01
    elif shared_Depth_buf[0] == 0x02:
        logging.info(f"{datetime.datetime.now()} - 主进程 : 检测到深度计运行时串口异常")
        return 0x02, 0x02
    elif shared_Depth_buf[0] == 0x00:
        logging.info(f"{datetime.datetime.now()} - 主进程 : 检测到深度计设备未初始化")

    if shared_IMU_buf == 0x10 and shared_Depth_buf == 0x10:  # 都初始化成功了,就亮
        return 0x00, 0x00
    if shared_Depth_buf == 0x09 or shared_IMU_buf == 0x09:
        return 0x09, 0x09
    return 0x0a, 0x0a

def setup_log_file():
    log_file_path = 'Data/log.txt'
    if os.path.exists(log_file_path):
        os.remove(log_file_path)
    os.mknod(log_file_path)
    os.chown(log_file_path, pwd.getpwnam('pi').pw_uid, grp.getgrnam('pi').gr_gid)
    os.chmod(log_file_path, 0o777)
    logging.basicConfig(filename='Data/log.txt', level=logging.INFO, filemode='w')
    logging.info(f"{datetime.datetime.now()} - 主进程 : 开始运行日志程序")

# 指示灯控制
def IndicatorLight():
    while True:
        dev,ErrCode = check_subprocess()
        if dev == 0x00 and ErrCode == 0x00: # 无设备异常
            controlIndicatorLight(True)
            time.sleep(5) # 直接延时过去了
        elif dev == 0x0a and ErrCode == 0x0a: # 设备在自检中，或者未知故障
            controlIndicatorLight(False)
            time.sleep(5)
        elif dev == 0x09 and ErrCode == 0x09: # 设备在自检中，或者未知故障
            controlIndicatorLight(True)
            time.sleep(1)
            controlIndicatorLight(False)
            time.sleep(1)
            controlIndicatorLight(True)
            time.sleep(1)
            controlIndicatorLight(False)
            time.sleep(1)
        else:
            led_stat = 0 
            controlIndicatorLight(led_stat) # 先熄灭500ms
            time.sleep(0.5)
            change_Per = float (2 / (dev * 2))
            for i in range(dev * 2):
                led_stat = not led_stat
                controlIndicatorLight(led_stat)
                time.sleep(change_Per)
            
            # 前面肯定是灭的状态
            controlIndicatorLight(led_stat)
            time.sleep(0.5)
            change_Per = float (1.5  / (ErrCode * 2))
            for i in range(ErrCode * 2):
                led_stat = not led_stat
                controlIndicatorLight(led_stat)
                time.sleep(change_Per)
            time.sleep(0.5)

if __name__ == '__main__':
    Datafolder = 'Data/'
    if not os.path.exists(Datafolder):
        os.makedirs(Datafolder)
        directory_path = os.path.dirname(Datafolder)
        # 获取 pi 用户的用户ID
        uid = pwd.getpwnam('pi').pw_uid
        # 获取 pi 用户的组ID
        gid = grp.getgrnam('pi').gr_gid
        # 修改目录权限，使 pi 用户可以读、写、执行
        os.chmod(directory_path, 0o777)
        # 更改目录的所有者为 pi 用户
        os.chown(directory_path, uid, gid)

    setup_log_file()
    t = threading.Thread(target=IndicatorLight, args=())
    t.start()
    print("主进程 : 指示灯数据接收线程开启成功")
    main()